package com.triangulator;

import java.util.Arrays;
import java.util.StringTokenizer;

import android.graphics.Color;
import android.util.Log;

public class HVHistogram {
	private final String TAG = "HVHist";
	private final float[] HBinEdges = {0, 36, 72, 108, 144, 180, 216, 252, 288, 324, 360};
	private final float[] VBinEdges = {0, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f};
	private int mNumColorBins = 10;
	private int mNumColors = 2;
	private int mNumBins = 20;
	
	private int [] mHistogram = null;
	
	private int mWidth;
	private int mHeight;
	private int mNumPixels;
	
	public HVHistogram() {
		mHistogram = null;
		mWidth = 0;
		mHeight = 0;
		mNumPixels = 0;
	}
	
	public HVHistogram(HVHistogram hist) {
		mWidth = hist.getWidth();
		mHeight = hist.getHeight();
		mNumPixels = hist.getNumPixels();

		mNumColorBins = hist.getNumColorBins();
		mNumColors = hist.getNumColors();
		mNumBins = hist.getNumBins();
		
		mHistogram = new int[mNumBins];
		System.arraycopy(hist.getHistogram(), 0, mHistogram, 0, mNumBins);
	}
	
	public HVHistogram(int image[], int image_width, int image_height) {
				
		initImage(image, image_width, image_height);
		/*
		mNumPixels = image.length;
		//mWidth = image_width;
		//mHeight = image_height;

		computeHistogram(image);
		*/
	}
	
	public HVHistogram(String str)	{
		StringTokenizer st = tokenizeString(str);
		
		Log.w(TAG,  str);
		
		mNumColorBins = Integer.parseInt(st.nextToken());
		mNumColors = Integer.parseInt(st.nextToken());
		mNumBins = Integer.parseInt(st.nextToken());
		mWidth = Integer.parseInt(st.nextToken());
		mHeight = Integer.parseInt(st.nextToken());
		mNumPixels = Integer.parseInt(st.nextToken());
		
		if (st.countTokens() != mNumBins +1) {
			Log.e(TAG, "Incorrect number of inputs in string: " + st.countTokens() + " not " + mNumBins);
			return;
		}
		
		mHistogram = new int[mNumBins];
		for (int b=0; b<mNumBins; b++) {
			mHistogram[b] = Integer.parseInt(st.nextToken());
		}
		
		Reidentificator.mScaleWidthRatio = Float.parseFloat(st.nextToken());
		Log.w(TAG, "set mScaleWidthRatio: " + Reidentificator.mScaleWidthRatio);
		
		Log.d(TAG, this.toString());
	}
	
	public void initImage(int image[], int image_width, int image_height) {		
		if (mHistogram == null) {
			mNumPixels = image.length;
			mWidth = image_width;
			mHeight = image_height;

			computeHistogram(image);
		}
	}
	
	public void computeHistogram(int image[]) {
		int pixel;
		float [] hsv = new float[3];
		
		if (mHistogram == null) {
			mHistogram = new int[mNumBins];
		} else {
			Log.d(TAG, "Re-computing histogram");
			
			Arrays.fill(mHistogram, 0);
		}
		
		int h_bin, v_bin;
		
		for (int i=0; i<image.length; i++) {
			pixel = image[i];
			
			Color.colorToHSV(pixel, hsv);
			h_bin = getHBin(hsv[0]);
			//s_bin = getSVBin(hsv[1]);
			v_bin = getVBin(hsv[2]);
			
			mHistogram[h_bin]++;
			//mHistogram[s_bin+10]++;
			mHistogram[v_bin+mNumColorBins]++;
		}
		
		/*
		String hist_string = new String();
		
		for (int i=0; i<mHistogram.length; i++) {
			hist_string += mHistogram[i] + " ";
		}
		*/
		
		//Log.d(TAG, hist_string); //histogram[0] + " " + histogram[10] + " " + histogram[20]);
	}
	
	public int getHBin(float h_value) {
		int bin = 0;
		
		while (h_value >= HBinEdges[bin+1])
			bin++;
		
		return bin;
	}
	
	public int getVBin(float sv_value) {
		int bin = 0;

		if (sv_value == 1.0f) {
			bin = 9;
		} else {while (sv_value >= VBinEdges[bin+1])
			bin++;
		}
		
		return bin;
	}
	
	
	public double histogramIntersection(HVHistogram hist) {
		if (mNumPixels != hist.getNumPixels()) {
			Log.e(TAG, "Number of pixels don't match");
			return -1;
		}
		
		double dist = 0;
		for (int b=0; b<mNumBins; b++) {
			dist += (double)(Math.min(this.getHistogram(b), hist.getHistogram(b)))/(double)(mNumPixels*3);
			//Log.d(TAG, b + " " + this.getHistogram(b) + " " + hist.getHistogram(b) + " => " + dist);
		}
		
		return dist;
	}
	
	public void add (HVHistogram h2, int new_width, int new_height) {
		this.setNumPixels(this.getNumPixels()+h2.getNumPixels());
		this.setHeight(new_height);
		this.setWidth(new_width);
		for (int b=0; b<this.getNumBins(); b++) {
			this.setHistogram(b, this.getHistogram(b)+h2.getHistogram(b));
		}
	}
	
	public void add (HVHistogram h2, HVHistogram h3, int new_width, int new_height) {
		this.setNumPixels(this.getNumPixels()+h2.getNumPixels()+h3.getNumPixels());
		this.setHeight(new_height);
		this.setWidth(new_width);
		for (int b=0; b<this.getNumBins(); b++) {
			this.setHistogram(b, this.getHistogram(b)+h2.getHistogram(b)+h3.getHistogram(b));
		}
	}
	
	public void subtract (HVHistogram h2, int new_width, int new_height) {
		this.setNumPixels(this.getNumPixels()-h2.getNumPixels());
		this.setHeight(new_height);
		this.setWidth(new_width);
		for (int b=0; b<this.getNumBins(); b++) {
			this.setHistogram(b, this.getHistogram(b)-h2.getHistogram(b));
		}
	}
	
	public int getPixelIndex (int x, int y) {
		return y*mWidth+x;
	}
	
	public int[] getHistogram() {
		return mHistogram;
	}
	
	public int getHistogram(int b) {
		return mHistogram[b];
	}
	
	public void setHistogram(int b, int value) {
		mHistogram[b] = value;
	}
	
	public int getNumBins() {
		return mNumBins;
	}
	
	public int getNumColorBins() {
		return mNumColorBins;
	}
	
	public int getNumColors() {
		return mNumColors;
	}
	
	public int getNumPixels() {
		return mNumPixels;
	}
	
	public void setNumPixels(int num_pixels) {
		mNumPixels = num_pixels;
	}
	
	public int getWidth() {
		return mWidth;
	}
	
	public int getHeight() {
		return mHeight;
	}
	
	public void setWidth(int width) {
		mWidth = width;
	}
	
	public void setHeight(int height) {
		mHeight = height;
	}
	
	public StringTokenizer tokenizeString(String histStr) {
		String delims = "[ ]*=";
		StringTokenizer st = new StringTokenizer(histStr, delims);
		
		return st;
	}
	
	public String toString() {
		String out = new String();
		
		out = "[" + mNumColorBins + "*" + mNumColors + "=" + mNumBins + " " + mWidth + "*" + mHeight + "=" + mNumPixels + "] ";
		
		if (mHistogram == null) {
			out += "NULL Histogram";
		} else {
			for (int i=0; i<mNumBins; i++) {
				out += mHistogram[i] + " ";
			}
		}
		
		return out;
	}
}
